﻿// -----------------------------------------------------------------------
// Copyright (c) David Kean. All rights reserved.
// -----------------------------------------------------------------------
extern alias pcl;
using System;
using System.IO;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using pcl::System.Adaptation;

namespace Portable.Adaptation
{
    [TestClass]
    public class ProbingAdapterResolverTests
    {
        [TestMethod]
        public void Resolve_PassesFalseAsThrowOnErrorToAssemblyGetType()
        {
            bool? result = null;
            var assembly = AssemblyFactory.OverrideGetType((name, throwOnError) => { result = throwOnError; return typeof(object); });
            var resolver = new ProbingAdapterResolver(assemblyString => assembly, "Unknown");

            resolver.Resolve(typeof(IAppDomainSetup));

            Assert.IsFalse(result.Value);
        }

        [TestMethod]
        public void Resolve_PassesTypeNameMinusIToAssemblyGetType()
        {
            string result = null;
            var assembly = AssemblyFactory.OverrideGetType((name, throwOnError) => { result = name; return typeof(object); });
            var resolver = new ProbingAdapterResolver(assemblyString => assembly, "Unknown");

            resolver.Resolve(typeof(IAppDomainSetup));

            Assert.AreEqual("System.AppDomainSetup", result);
        }

        [TestMethod]
        public void Resolve_PassesCorrectAssemblyNameToAssemblyLoader()
        {
            string result = null;
            var resolver = new ProbingAdapterResolver(assemblyString => { result = assemblyString; return typeof(object).Assembly; }, "Unknown");

            resolver.Resolve(typeof(IAppDomainSetup));

            AssemblyName name = new AssemblyName(result);

            Assert.AreEqual(name.Name, "Portable.Unknown");
        }

        [TestMethod]
        public void Resolve_WhenPlatformSpecificAssemblyNotFound_ThrowsInvalidOperation()
        {
            var resolver = new ProbingAdapterResolver(assemblyString => { throw new FileNotFoundException(); }, "Desktop");

            ExceptionAssert.Throws<InvalidOperationException>(() =>
            {
                resolver.Resolve(typeof(IAppDomainSetup));
            });
        }

        [TestMethod]
        public void Resolve_WhenAdapterNotFound_ReturnsNull()
        {
            var resolver = new ProbingAdapterResolver(assemblyString => typeof(object).Assembly, "Desktop");

            var result = resolver.Resolve(typeof(IDisposable));

            Assert.IsNull(result);
        }

        [TestMethod]
        public void Resolve_KeepsProbingUntilAdapterIsFound()
        {
            int count = 0;
            var resolver = new ProbingAdapterResolver(assemblyString => count++ == 0 ? null : typeof(object).Assembly, "Unknown", "Desktop");

            var result = resolver.Resolve(typeof(IAppDomainSetup));

            Assert.IsInstanceOfType(result, typeof(AppDomainSetup));
        }

        [TestMethod]
        public void Resolve_SameTypeMultipleTimes_ReturnsSameInstances()
        {
            var resolver = new ProbingAdapterResolver(assemblyString => typeof(object).Assembly, "Desktop");

            var result1 = resolver.Resolve(typeof(IAppDomainSetup));
            var result2 = resolver.Resolve(typeof(IAppDomainSetup));

            Assert.AreSame(result1, result2);
        }
    }
}
